/*
 * LS.cpp
 *
 *  Created on: 22/06/2011
 *      Author: daniel
 */

#include "LS.h"
#include "Operator.h"
#include <iostream>
#include <stdio.h>
using namespace std;

/**
 * Aplica busqueda local a una solucion inicial. (Primer Mejor)
 * @param: un apuntador a una solucion inicial.
 * @return: un optimo local.
 */
Solution* LS::LocalSearch(Solution *is, int maxIter, int stuck) {

	Solution *sact = is;
	Solution *sP;

	sact->iniCost = sact->cost;
	vector<int*> neighbors = Operator::twoOptNeighborhood(sact);

	int i = 0; // Contador de iteraciones.
	int j = 0; // Contador de intentos de mejoras.

	while (!neighbors.empty() && i < maxIter && j < stuck) {

		int* chosen = neighbors.back();
		neighbors.pop_back();
		sP = sact->swap(chosen[0], chosen[1]);

		if (sP->cost < sact->cost) {
			sact = sP->clone();

			// Borra la basura de la memoria.
			while (!neighbors.empty()) {
				delete[] neighbors.back();
				neighbors.pop_back();
			}

			//neighbors.clear();
			neighbors = Operator::twoOptNeighborhood(sact);

			j = 0;
		}

		delete[] chosen;
		delete sP;

		i++;
		j++;
	}

	// Guarda el numero de iteraciones.
	if (i < j)
		sact->numIter = i;
	else
		sact->numIter = j;

	return sact;
}

/**
 * Aplica busqueda local a una solucion inicial (Mejor-mejor).
 * @param: un apuntador a una solucion inicial.
 * @return: un optimo local.
 */
Solution* LS::LocalSearchBI(Solution *is, int maxIter, int stuck) {

	Solution *sact;
	Solution *sopt = is->clone();

	vector<int*> neighborhood = Operator::threeOptNeighborhood(sopt);
	bool hasImproved = false;

	int i = 0; // Contador de iteraciones.
	int j = 0; // Contador de intentos de mejoras.

	while (!neighborhood.empty() && i < maxIter && j < stuck) {

		int* chosen = neighborhood.back();
		neighborhood.pop_back();

		sact = sopt->swap(chosen[0], chosen[1]);

		// Cuando encuentra uno mejor, actualiza.
		if (sact->cost <= sopt->cost) {
			sopt = sact->clone();
			j = 0;
			hasImproved = true;
		}

		// Si se queda sin vecinos, sigue buscando.
		if (neighborhood.empty() && hasImproved) {
			neighborhood = Operator::threeOptNeighborhood(sact);
			hasImproved = false;
		}

		delete[] chosen;
		delete sact;

		i++;
		j++;
	}

	// Guarda el costo inicial para control.
	sopt->iniCost = is->cost;

	// Guarda el numero de iteraciones.
	if (i < j)
		sopt->numIter = i;
	else
		sopt->numIter = j;

	return sopt;
}

